package com.cooper.android.comm;

import java.util.LinkedHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> {
	/**
	 * 
	 */
	private static final long serialVersionUID = -8850099389152491930L;

	private final int maxCapacity;
	private static final float DEFAULT_LOAD_FACTOR = 0.75f;
	private final Lock lock = new ReentrantLock();
	private RemoveEldestEntryListener<K, V> removeEldestEntryListener;

	public LRULinkedHashMap(int maxCapacity) {
		super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
		this.maxCapacity = maxCapacity;
	}

	public RemoveEldestEntryListener<K, V> getRemoveEldestEntryListener() {
		return removeEldestEntryListener;
	}

	public void setRemoveEldestEntryListener(
			RemoveEldestEntryListener<K, V> removeEldestEntryListener) {
		this.removeEldestEntryListener = removeEldestEntryListener;
	}

	@Override
	protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
		boolean result = size() > maxCapacity;
		if (removeEldestEntryListener != null) {
			if (result)
				return removeEldestEntryListener.onRemove(eldest);
			else
				return false;
		} else
			return result;
	}

	@Override
	public V get(Object key) {
		lock.lock();
		try {
			return super.get(key);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public V put(K key, V value) {
		lock.lock();
		try {
			return super.put(key, value);
		} finally {
			lock.unlock();
		}
	}

	@Override
	public void clear() {
		lock.lock();
		try {
			if (removeEldestEntryListener != null) {
				for (java.util.Map.Entry<K, V> entry : entrySet()) {
					removeEldestEntryListener.onRemove(entry);
				}
			}
			super.clear();
		} finally {
			lock.unlock();
		}
	}

	public interface RemoveEldestEntryListener<K, V> {

		public abstract boolean onRemove(java.util.Map.Entry<K, V> eldest);
	}
}